/*******************************************************************/
/* @ All Rights Reserved Copyright (C) 2014 broada,Co.,Ltd.        */
/*                                                                 */
/*  NAME      = frssl_main.c                                       */
/*  NOTE      = ssl解析入口                                        */
/*  DATE      = 2016/01/26 by guojq                                */
/*******************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <getopt.h>
#include <unistd.h>
#include <errno.h>
#include <pcap/pcap.h>
#include <pthread.h>

#include <wolfssl/wolfcrypt/settings.h>
#include <cyassl/sniffer.h>

#include "frcomm.h"
#include "frlog.h"
#include "frmem.h"
#include "frshm_pool.h"
#include "frsem.h"
#include "frshm_stat.h"

#include "frssl_daq.h"
#include "frdssl.h"
#include "frssl_config.h"
#include "frssl_task_do.h"
#include "frssl_decode.h"

FR_STATIC pthread_spinlock_t   g_spin_ssl_zmq_lock;
#ifdef FRTEST_REPORT
FR_STATIC unsigned long g_ul_send_all = 0;
unsigned long g_ul_pcap_receive_all = 0;
unsigned long g_ul_parse_all = 0;
FR_STATIC unsigned long g_arr_ul_send[4] = {0,0,0,0};
FR_STATIC unsigned long g_arr_pcap_receive[4] = {0,0,0,0};
unsigned long g_arr_parse[4] = {0,0,0,0};
FR_STATIC pthread_t     g_thread_id_report=NULL;
//是否打印到debuglog的开关 (1:打印  0:不打印)默认打印
FR_STATIC int g_i_report_flag = 1;
#endif

//程序运行标志
int g_i_flag_run = 1;
//共享内存ID
static int g_i_share_mem = 0;
//进程锁
static int g_i_semaphore = 0;
//pcap连接状态
static int g_i_pcap_linktype = 0;
//tcpdump数据包。抓包完成时
static int g_i_pcap_done = 0;

FR_STATIC pthread_t g_thread_id_chk_dump=0;
DAQ_PktHdr_t *frssl_last_pcap_header = NULL;
u_char *frssl_last_pcap_data = NULL;
FR_STATIC pthread_t *g_p_thread_id_do_task=NULL;
FR_STATIC unsigned int g_ui_threads=1;  //总线程个数(包括主线程)
FR_STATIC int *g_p_i_task_loop;

static Frmemstat_mng g_st_memstat_mng={0,FR_MEMSTAT_COUNT_MAX};
static pthread_rwlock_t  g_memstat_rwlock = PTHREAD_RWLOCK_INITIALIZER;
static Frmem_env g_st_mem_env = {&g_st_memstat_mng, &g_memstat_rwlock};

#ifndef FRSSL_SHM
    #include <zmq.h>
    
    FR_STATIC void *p_st_zmq_context = NULL;
    FR_STATIC void *p_st_zmq_sender=NULL;
    FR_STATIC int g_i_zmq_init = 0;
#endif

#define APM_CFG_FILENAME_ZLOG             "../conf/zlog.conf"       /* zlog配置文件 */

enum {
    ETHER_IF_FRAME_LEN = 14,   /* ethernet interface frame length */
    NULL_IF_FRAME_LEN =   4,   /* no link interface frame length  */
};

FR_STATIC void __usage(char *p_pgname)
{
    printf("Usage: %s [OPTION]... \n", p_pgname);
    printf("param info\n");
    printf("\t-d 测试用pcap文件\n");
    printf("\t-n 不进行checksum检查.(暂时都不检查checksum)\n");
    printf("\t-i 网卡设备名 (eg. -i eth2). (default eth0)\n");
    printf("\t--cap_type (抓包类型,文件读取时无效), 0:pcap 1:afpacket, 默认 pcap eg. --cap_type 1\n");
    printf("\t--snaplen (抓取数据包长度,数据包文件获取时无效. 单位byte, eg. --snaplen 16384), 最大65535, 默认 16384\n");
    printf("\t--ring_size (ring buffer size 单位M, eg. --ring_size 128). 范围 4(4M) - 2048(2048M)\n");
    printf("\t发送USR2信号能开启/关闭 debug日志中显示的统计信息\n");
    printf("\t-h/--help help.\n");
    
}

/*******************************************************************************
*  FUNC     :  退出sniffer ssl解密
*  ARGS     :  
*  RTN      :  void
*  NOTE     :
*******************************************************************************/
FR_STATIC void __ssl_sniffer_exit(void)
{
    DAQ_Stop();
    DAQ_Unload();
    ssl_FreeSniffer();
}

/*******************************************************************************
*  FUNC     :  退出ssl解密
*  ARGS     :  
*  RTN      :  void
*  NOTE     :
*******************************************************************************/
FR_STATIC void __ssl_exit(void)
{
    int i_loop = 0;
    
    if (g_p_i_task_loop)
        frfree(g_p_i_task_loop);
        
    if(g_thread_id_chk_dump)
        pthread_join(g_thread_id_chk_dump, NULL);
    for(i_loop=0; g_p_thread_id_do_task && i_loop<g_i_dssl_task_cnt; i_loop++)
    {
        if(g_p_thread_id_do_task[i_loop])
            pthread_join(g_p_thread_id_do_task[i_loop], NULL);
    }
    if(g_p_thread_id_do_task)
    {
        frfree(g_p_thread_id_do_task);
        g_p_thread_id_do_task = NULL;
    }
#ifdef FRTEST_REPORT
    if(g_thread_id_report)
        pthread_join(g_thread_id_report, NULL);
#endif
    
    frtask_info_exit();
    
    __ssl_sniffer_exit();
    
#ifndef FRSSL_SHM
    if(p_st_zmq_sender)
    {
        zmq_close(p_st_zmq_sender);
        p_st_zmq_sender = NULL;
    }
    if(p_st_zmq_context)
    {
        zmq_term(p_st_zmq_context);
        p_st_zmq_context = NULL;
    }
#endif
}

#ifdef FRTEST_REPORT

//sleep时间
FR_STATIC int g_i_timeout = 1;

FR_STATIC unsigned long __frdbg_count_avg(unsigned long arr_ul_last[4])
{
    if (arr_ul_last[0] == 0 || arr_ul_last[1] == 0)
    {
        //记录的是总数，因此前2个节点为0的情况说明平均为0或者是刚开始统计，平均设成0
        return 0;
    }
    if (arr_ul_last[2] == 0)
    {
        return (arr_ul_last[0] - arr_ul_last[1])/g_i_timeout;
    }
    if (arr_ul_last[3] == 0)
    {
        return (arr_ul_last[0] - arr_ul_last[2])/(g_i_timeout*2);
    }
    return (arr_ul_last[0] - arr_ul_last[3])/(g_i_timeout*3);
}

FR_STATIC void *__frdbg_report_ssl(void *arg)
{
    unsigned long ul_send_avg = 0;
    unsigned long ul_pcap_avg = 0;
    unsigned long ul_parse = 0;
    
    while (g_i_flag_run)
    {
        memmove(g_arr_ul_send+1, g_arr_ul_send, sizeof(unsigned long)*3);
        memmove(g_arr_pcap_receive+1, g_arr_pcap_receive, sizeof(unsigned long)*3);
        memmove(g_arr_parse+1, g_arr_parse, sizeof(unsigned long)*3);
        
        g_arr_ul_send[0] = g_ul_send_all;
        g_arr_pcap_receive[0] = g_ul_pcap_receive_all;
        g_arr_parse[0] = g_ul_parse_all;
        ul_send_avg = __frdbg_count_avg(g_arr_ul_send);
        ul_pcap_avg = __frdbg_count_avg(g_arr_pcap_receive);
        ul_parse = __frdbg_count_avg(g_arr_parse);
            
        if (g_i_report_flag)
        {
            FRLOG_DEBUG("ssl pcap_receive:[%lu %lu/s] parse:[%lu %lu/s] queue:[%d] zmq_send:[%lu %lu/s]"
                       , g_ul_pcap_receive_all, ul_pcap_avg
                       , g_ul_parse_all, ul_parse
                       , frssl_task_list_count()
                       , g_ul_send_all, ul_send_avg);
        }
        sleep(g_i_timeout);
    }
    return NULL;
}
#endif

/*******************************************************************************
*  FUNC     :  初始化pcap句柄
*  ARGS     :  pcap(命令行)
*  RTN      :  0 (success)
*           :  其他 (failed)
*  NOTE     :
*******************************************************************************/
FR_STATIC int __daq_init(int i_module_type)
{
    const char *arr_dirs[]={"/usr/local/lib/daq", NULL};
    const char *p_module_name=DAQ_MODULE_PCAP;
    int i_ret_fun=0;
    
    i_ret_fun = DAQ_Load(arr_dirs);
    if(i_ret_fun != DAQ_SUCCESS)
    {
        FRLOG_ERROR("DAQ_Load error");
        return DAQ_ERROR;
    }
    if(i_module_type == 1)
        p_module_name = DAQ_MODULE_AFPACKET;
    
    i_ret_fun = DAQ_Init(p_module_name);
    if(i_ret_fun != DAQ_SUCCESS)
    {
        FRLOG_ERROR("DAQ_Init error");
        DAQ_Unload();
        return DAQ_ERROR;
    }

    return DAQ_SUCCESS;
}

/*******************************************************************************
*  FUNC     :  把进程的pid写到临时目录
*  ARGS     :  
*  RTN      :  
*  NOTE     :
*******************************************************************************/
FR_STATIC void __write_pid(void)
{
    FILE *fp = NULL;
    
    fp = fopen(SSL_PID_FILE, "w");
    if (fp)
    {
        fprintf(fp, "%d", getpid());
        fclose(fp);
    }
}

FR_STATIC void *__frame_chk_dump_close(void *arg)
{
    int i_loop=0;
    
    //等待3sec
    for(i_loop=0; i_loop < 3; i_loop++)
    {
        printf("dump file mode, wait for do pcap %dsec...\n"
                , i_loop+1);
        sleep(1);
    }
    
    do
    {
        if (g_i_pcap_done && frssl_task_done() == FR_SUCC)
        {
            g_i_flag_run = 0;
            break;
        }
        sleep(1);
    } while(g_i_flag_run);
    
    pthread_exit(0);

    return (void*)NULL;
}

FR_STATIC int __ssl_thread_init(int i_flag_is_dump)
{
    int i_ret_fun = 0;
    int i_loop = 0;
    
    if (g_i_dssl_task_cnt <= 0)
        return FR_FAIL;
        
    if (i_flag_is_dump)
    {
        i_ret_fun = pthread_create(&g_thread_id_chk_dump, NULL, __frame_chk_dump_close, NULL);
        if(i_ret_fun)
        {
            FRLOG_ERROR_DETAIL("pthread_create __frame_chk_dump_close err");
            goto ERROR;
        }
    }
        
#ifdef FRTEST_REPORT
    i_ret_fun = pthread_create(&g_thread_id_report, NULL, __frdbg_report_ssl, NULL);
    if(i_ret_fun)
    {
        FRLOG_ERROR_DETAIL("pthread_create __frdbg_report_ssl err");
        goto ERROR;
    }
#endif

    g_p_thread_id_do_task = (pthread_t *) frmalloc(sizeof(pthread_t) * g_i_dssl_task_cnt);
    if(g_p_thread_id_do_task == NULL)
    {
        FRLOG_ERROR_DETAIL("frmalloc err");
        goto ERROR;
    }
    memset(g_p_thread_id_do_task, '\0', sizeof(pthread_t) * g_i_dssl_task_cnt);
    
    g_p_i_task_loop = (int *)frmalloc(sizeof(int) *g_i_dssl_task_cnt);
    for(i_loop=0; i_loop<g_i_dssl_task_cnt; i_loop++)
    {
        *(g_p_i_task_loop + i_loop) = i_loop;
    }
    
    for(i_loop=0; i_loop<g_i_dssl_task_cnt; i_loop++)
    {
        i_ret_fun = pthread_create(g_p_thread_id_do_task+i_loop, NULL, frssl_task_do, (void *)g_p_i_task_loop[i_loop]);
        if(i_ret_fun)
        {
            *(g_p_thread_id_do_task+i_loop) = 0;
            FRLOG_ERROR_DETAIL("pthread_create frtask_do num=[%d] err", i_loop);
            continue;
        }
        g_ui_threads++;
    }

    return FR_SUCC;
ERROR:
    if(g_thread_id_chk_dump)
        pthread_join(g_thread_id_chk_dump, NULL);
#ifdef FRTEST_REPORT
    if(g_thread_id_report)
        pthread_join(g_thread_id_report, NULL);
#endif
    for(i_loop=0; g_p_thread_id_do_task && i_loop<g_i_dssl_task_cnt; i_loop++)
    {
        if(g_p_thread_id_do_task[i_loop])
            pthread_join(g_p_thread_id_do_task[i_loop], NULL);
    }
    return FR_FAIL;
}

/*******************************************************************************
*  FUNC     :  初始化sniffer ssl
*  ARGS     :  
*  RTN      :  FR_SUCC (success)
*           :  FR_FAIL (failed)
*  NOTE     :
*******************************************************************************/
FR_STATIC int __ssl_init(int i_flag_is_dump)
{
    char arr_err[PCAP_ERRBUF_SIZE];
    int i_ret_fun = 0;
    
    //保存本程序的pid
    __write_pid();
    
    //初始化sniffer
    ssl_InitSniffer();
    //设置tracelog文件
    if (APM_DSSL_DEBUG)
        ssl_Trace("../logs/tracefile.txt", arr_err);
    //设置使用内存的大小 
    ssl_EnableRecovery(1, -1, arr_err);

    if (frssl_config_init() != FR_SUCC)
    {
        FRLOG_ERROR("frssl_config_init error");
        return FR_FAIL;
    }

    //读取配置文件的信息
    frssl_config_load();

#ifdef FRSSL_SHM
    g_i_share_mem = frshm_pool_get(SHM_FILE);
    if (g_i_share_mem < 0)
    {
        FRLOG_ERROR("frshm_pool_get error [%s]", strerror(errno));
        return FR_FAIL;
    }
    g_i_semaphore = frsem_get(SEM_FILE);
    if (g_i_semaphore < 0)
    {
        FRLOG_ERROR("frsem_get error [%s]", strerror(errno));
        return FR_FAIL;
    }
    
    if (frshm_stat_get() != FR_SUCC)
    {
        FRLOG_ERROR("frshm_stat_get error [%s]", strerror(errno));
        return FR_FAIL;
    }
#else
    int i_send_timeout = 100;
    p_st_zmq_context = zmq_init(1);
    if (p_st_zmq_context == NULL)
    {
        FRLOG_ERROR_DETAIL("zmq_init err");
        return FR_FAIL;
    }
    
    p_st_zmq_sender = zmq_socket(p_st_zmq_context,ZMQ_PUSH);
    if (p_st_zmq_sender == NULL)
    {
        FRLOG_ERROR_DETAIL("zmq_socket err");
        zmq_term(p_st_zmq_context);
        return FR_FAIL;
    }

    int option_sndhwm = 10000;
    zmq_setsockopt(p_st_zmq_sender, ZMQ_SNDHWM, &option_sndhwm, sizeof(option_sndhwm));

    i_ret_fun = zmq_connect(p_st_zmq_sender, g_arr_dssl_zmq_client);
    if (i_ret_fun != 0)
    {
        FRLOG_ERROR_DETAIL("zmq_connect err");
        zmq_term(p_st_zmq_context);
        zmq_close(p_st_zmq_sender);
        return FR_FAIL;
    }
    zmq_setsockopt(p_st_zmq_sender, ZMQ_SNDTIMEO, &i_send_timeout, sizeof(int));
    g_i_zmq_init = 1;
#endif
    
    //初始化任务处理线程的信息
    if (frtask_info_init() != FR_SUCC)
    {
        FRLOG_ERROR("frtask_info_init error");
        goto err;
    }
    
    if (__ssl_thread_init(i_flag_is_dump) != FR_SUCC)
    {
        FRLOG_ERROR("ssl thread init error");
        frtask_info_exit();
        goto err;
    }
    
    
    return FR_SUCC;
err:
    return FR_FAIL;
}

/*******************************************************************************
*  FUNC     :  信号处理
*  ARGS     :  dunno    (信号量)
*  RTN      :  
*  NOTE     :
*******************************************************************************/
FR_STATIC void __frame_sig(int dunno)
{
    switch (dunno) {
        case SIGHUP:
            //g_i_flag_run = 0;
            //event_base_loopbreak(g_p_st_ebase);
            FRLOG_INFO("SIGHUP\n");
            break;
        case SIGINT:
            if(g_i_flag_run)
            {
                g_i_flag_run = 0;
                FRLOG_INFO("signal exit");
            }
            FRLOG_INFO("SIGINT\n");
            break;
        case SIGQUIT:
            if(g_i_flag_run)
            {
                g_i_flag_run = 0;
                FRLOG_INFO("signal exit");
            }
            FRLOG_INFO("SIGQUIT\n");
            break;
        case SIGPIPE:
            FRLOG_INFO("SIGPIPE\n");
            break;
        case SIGUSR1:
            FRLOG_INFO("SIGUSR1\n");
            frssl_config_load();
            break;
        case SIGUSR2:
            FRLOG_INFO("SIGUSR2\n");
            if (g_i_report_flag)
                g_i_report_flag = 0;
            else
                g_i_report_flag = 1;
            break;
        default:
            break;
    }
    return;
}

/*******************************************************************************
*  FUNC     :  把解密后的信息写入共享内存
*  ARGS     :  p_data(解密后的内容)
*           :  i_data_len(解密后的内容长度)
*           :  p_st_info(ip信息)
*           :  i_type(数据的类型[syn、fin、data])
*  RTN      :  FR_SUCC (success)
*           :  FR_FAIL (failed)
*  NOTE     :
*******************************************************************************/
FR_STATIC int __frssl_shm_write(unsigned char *p_data, int i_data_len
                           , sniffer_ipinfo *p_st_info, struct timeval *p_st_ts
                           , int i_type)
{
    ssl_decode *p_decode = NULL;
    
    if (p_st_info == NULL)
        return FR_FAIL;
    
    if (frssl_mk_decode(p_data, i_data_len, i_type, p_st_info, p_st_ts, &p_decode) != FR_SUCC)
        return FR_FAIL;
        
#ifdef FRSSL_SHM
    frsemaphore_lock(g_i_semaphore);
    if (frshm_pool_write(g_i_share_mem, p_decode, sizeof(ssl_decode) + i_data_len) < 0)
    {
        frsemaphore_unlock(g_i_semaphore);
        if (p_decode)
            frfree(p_decode);
        return FR_FAIL;
    }
    frsemaphore_unlock(g_i_semaphore);
#else
    if (g_i_zmq_init == 0)
    {
        if (p_decode)
            frfree(p_decode);
        return FR_FAIL;
    }
    int i_ret_fun = zmq_send(p_st_zmq_sender, p_decode, sizeof(ssl_decode) + i_data_len, 0);
    if (i_ret_fun < 0)
    {
        usleep(10000);
    }
#endif

#ifdef FRTEST_REPORT
    g_ul_send_all++;
#endif
    
    frfree(p_decode);
    
    return FR_SUCC;
}

int frssl_decode(Frssl_thread *p_ssl_org)
{
    unsigned char* p_decode_data = NULL;
    char arr_err[PCAP_ERRBUF_SIZE];
    int i_data_len = 0;
    int i_ret = 0;
    
    if (p_ssl_org == NULL)
        return FR_FAIL;
        
    //上报syn、fin的信息
    if (p_ssl_org->st_option.i_conn_type != SSL_TYPE_DATA)
    {
        pthread_spin_lock(&g_spin_ssl_zmq_lock);
        i_ret = __frssl_shm_write(NULL, 0, &p_ssl_org->st_option.st_ipinfo
                , &p_ssl_org->st_option.st_ts, p_ssl_org->st_option.i_conn_type);
        pthread_spin_unlock(&g_spin_ssl_zmq_lock);
        if (i_ret != FR_SUCC)
            return FR_FAIL;
    }
    
    i_data_len = ssl_DecodePacket((const unsigned char *)p_ssl_org->p_encode, p_ssl_org->i_encode_len
                , &p_decode_data, arr_err);
    if (i_data_len <= 0)
    {
        if (p_decode_data)
            ssl_FreeDecodeBuffer(&p_decode_data, arr_err);
        return FR_FAIL;
    }
    else if (i_data_len > 0)
    {
        //写入共享内存
        p_decode_data[i_data_len] = 0;
        pthread_spin_lock(&g_spin_ssl_zmq_lock);
        i_ret = __frssl_shm_write(p_decode_data, i_data_len
                    , &p_ssl_org->st_option.st_ipinfo
                    , &p_ssl_org->st_option.st_ts, p_ssl_org->st_option.i_conn_type);
        pthread_spin_unlock(&g_spin_ssl_zmq_lock);
        if (i_ret != FR_SUCC)
        {
            if (p_decode_data)
                ssl_FreeDecodeBuffer(&p_decode_data, arr_err);
            return FR_FAIL;
        }
        if (APM_DSSL_DEBUG)
        	printf("SSL App p_decode_data(%d)(ts.sec=%d):[%s]\n"
        	     , i_data_len, p_ssl_org->st_option.st_ts.tv_sec, p_decode_data);
        if (p_decode_data)
            ssl_FreeDecodeBuffer(&p_decode_data, arr_err);
    }
    return FR_SUCC;
}


/*******************************************************************************
*  FUNC     :  根据pcap连接状态和数据包头信息，计算ip头需要跳过的长度
*  ARGS     :  p_data(数据包内容)
*           :  i_len(数据包长度)
*           :  p_i_offset(需要跳过的长度)
*  RTN      :  FR_SUCC (success)
*           :  FR_FAIL (failed、数据包错误)
*  NOTE     :
*******************************************************************************/
FR_STATIC int __pcap_chk_linktype(const unsigned char *p_data, int i_len, int *p_i_offset)
{
    int i_linkoffset = 14;
    
    switch (g_i_pcap_linktype) {
        case DLT_EN10MB:
        {
            int i_offset = 12;
            
check_ip_type:
            if (i_len < i_offset + 2)
                return FR_FAIL;
            /* Only handle IP packets and 802.1Q VLAN tagged packets below. */
        	if (p_data[i_offset] == 8 && p_data[i_offset + 1] == 0) {
                /* Regular ethernet */
                break;
            } else if (p_data[i_offset] == 0x81 && p_data[i_offset + 1] == 0) {
                /* Skip 802.1Q VLAN and priority information */
                i_linkoffset += 4;
                i_offset += 4;
                goto check_ip_type;
            } else if (p_data[i_offset] == 0x88 && p_data[i_offset + 1] == 0x47) {
                /* Skip mpls */
                i_linkoffset += 4;
            } else if (p_data[i_offset] == 0x88 && p_data[i_offset + 1] == 0x48) {
                /* Skip mpls multi */
                i_linkoffset += 4;
            } else if (p_data[i_offset] == 0x88 && p_data[i_offset + 1] == 0x64) {
                /* Skip pppoe */
                i_linkoffset += 8;
            }
        	else
                /* non-ip frame */
                return FR_FAIL;
        }
        break;
    }
    *p_i_offset = i_linkoffset;
    return FR_SUCC;
}

static void __ssl_pcap_handler(u_char * par, DAQ_PktHdr_t *header, u_char * p_packet)
{
    int i_frame = 0; 

    frssl_last_pcap_header = header;
    frssl_last_pcap_data = p_packet;
    
    if (header->caplen <= 40) /* min ip(20) + min tcp(20) */
        return;
    
	if (__pcap_chk_linktype(p_packet, header->caplen, &i_frame) != FR_SUCC)
        return;
    
	p_packet    += i_frame;
	header->caplen -= i_frame;

    frssl_task_add(p_packet, header);
    return;
}

static DAQ_Verdict ssl_pcap_handler(void* user, const DAQ_PktHdr_t* pkthdr, const uint8_t* pkt)
{
    __ssl_pcap_handler((u_char *)user, (DAQ_PktHdr_t *)pkthdr, (u_char *)pkt);
    return DAQ_VERDICT_PASS;
}

/*******************************************************************************
*  FUNC     :  sniffer ssl解码主程序
*  ARGS     :
*  RTN      :
*  NOTE     :
*******************************************************************************/
int main(int argc, char** argv)
{
    int i_flag_param = 0, i_flag_chksum = 0, i_flag_exit = 0;
    int i_ring_size=0, i_snaplen = 0, i_cap_type=0, i_pcap_time = 0;
    int i_flag_is_dump = 0;
    int i_ret = 0;
    char *p_dev = NULL;
    char *p_dumpfile = NULL;
    char arr_err[PCAP_ERRBUF_SIZE];
    
    const char *p_short_opts = "d:i:nh";
    struct option st_long_opts[] = { {"help", 0, NULL, 'H'},
                                     {"cap_type", 1, NULL, 'D'},
                                     {"snaplen", 1, NULL, 'N'},
                                     {"ring_size", 1, NULL, 'S'},
                                     {NULL, 0, NULL, 0} };
    
    //p_dev="eth0";
    while((i_flag_param=getopt_long(argc, argv, p_short_opts, st_long_opts, NULL) )!=-1)
    {
        switch(i_flag_param)
        {
            case 'd': //测试用pcap文件
              //frdbg("option d:[%s]\n",optarg);
              p_dumpfile = optarg;
              break;
            case 'D': //cap_type 0:pcap; 1:afpacket
                i_cap_type = atoi(optarg);
              if(i_cap_type < 0 || i_cap_type > 1)
                  i_cap_type = 0;
              break;
            case 'i': //网卡设备名
              p_dev = optarg;
              break;
            case 'n': //不进行checksum检查
              i_flag_chksum = FR_NO;
              break;
            case 'N': //snaplen 数据包长度
                i_snaplen = atoi(optarg);
              if(i_snaplen < 0)
                  i_snaplen = 0;
              else if(i_snaplen > 65535)
                  i_snaplen = 65535;
              break;
            case 'S': //ring buffer size
              i_ring_size = atoi(optarg);
              if(i_ring_size < 0)
                  i_ring_size = 0;
              else if(i_ring_size < 4 || i_ring_size > 2048) //< 4M || > 512M
                  i_ring_size = 128; //128M
              break;
            case 'H':
            case 'h':
              __usage(argv[0]);
              i_flag_exit = FR_YES;
              break;
        }
    }
    if(i_flag_exit == FR_YES)
        return 0;
    
    signal(SIGHUP, __frame_sig);
    signal(SIGINT, __frame_sig);
    signal(SIGQUIT, __frame_sig);
    signal(SIGPIPE, __frame_sig);
    signal(SIGUSR1, __frame_sig);
    
    pthread_spin_init(&g_spin_ssl_zmq_lock, 0);
    //设置默认值
    if (i_ring_size == 0)
        i_ring_size = 128;
    if (i_snaplen == 0)
        i_snaplen = 16384;
    i_pcap_time = 1024;

    i_ret = frlog_open(APM_CFG_FILENAME_ZLOG, "dssl");
    if (i_ret)
    {
        printf("log_open failed\n");
        return 1;
    }

    if( fr_slab_init( (&g_st_mem_env) , "frdssl") == NULL)
    {
        FRLOG_ERROR("fr_slab_init err");
        frlog_close();
        return 1;
    }

    if (p_dumpfile)
        i_flag_is_dump = 1;

    //初始化
    if (__ssl_init(i_flag_is_dump) != FR_SUCC)
        goto err;
    
    FRLOG_INFO("dssl init success");
    
    if (__daq_init(i_cap_type) != DAQ_SUCCESS)
        goto err;
    
    if (i_flag_is_dump)
    {
        i_ret = DAQ_New(DAQ_MODE_READ_FILE, p_dumpfile, i_ring_size
                      , i_snaplen, i_pcap_time, arr_err, sizeof(arr_err));
        if(i_ret != DAQ_SUCCESS)
            goto err;
    }
    else if (p_dev)
    {
        i_ret = DAQ_New(DAQ_MODE_PASSIVE, p_dev, i_ring_size, i_snaplen, i_pcap_time
                         , arr_err, sizeof(arr_err));
        if(i_ret != DAQ_SUCCESS)
            goto err;
    }
    else
    {
        __usage(argv[0]);
        goto err;
    }
    
    i_ret = DAQ_Start(arr_err, sizeof(arr_err));
    if(i_ret != DAQ_SUCCESS)
        goto err;
        
    g_i_pcap_linktype = DAQ_datalink();

    while (1)
    {
        if (g_i_flag_run == 0)
            break;
        
        if (i_flag_is_dump)
        {
            DAQ_Acquire(-1, ssl_pcap_handler, NULL);
            break;
        }
        DAQ_Acquire(1, ssl_pcap_handler, NULL);
    }

    g_i_pcap_done = 1;

    FRLOG_INFO("dssl normal exit");
    frssl_config_destroy();
    __ssl_exit();
    fr_slab_destroy();
    pthread_spin_destroy(&g_spin_ssl_zmq_lock);
    frlog_close();

    return 0;
err:
    frssl_config_destroy();
    __ssl_exit();
    fr_slab_destroy();
    pthread_spin_destroy(&g_spin_ssl_zmq_lock);
    frlog_close();
    return 1;
}

